package com.strong.utils.mvc.pojo.retrieve;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.strong.utils.StrongUtils;
import lombok.Data;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 查询DTO的抽象类
 *
 * @param <M> the entityType parameter
 * @author Simen
 * @version 1.0 2018-06-30 10:51:21
 */
@Data
@JsonPropertyOrder(alphabetic = true)
public abstract class RetrieveDTO<M> {

    @JsonIgnore
    private Class<M> classM;

    /**
     * 查询条件集合
     */
    private Map<String, String> mapSearch;

    /**
     * 排序条件集合
     */
    private Map<String, String> mapSort;

    /**
     * 排序对象
     */
    private Sort sort;

    /**
     * 查询参数模型
     */
    private M model;

    /**
     * 获得排序对象
     *
     * @return {@link Sort}
     */
    @JsonIgnore
    public Sort getSort() {
        if (ObjectUtil.isNull(sort) && CollUtil.isNotEmpty(mapSort)) {
            List<Sort.Order> listOrder = new ArrayList<>();
            for (String strKey : mapSort.keySet()) {
                if (mapSort.get(strKey).equals(getDescString())) {
                    listOrder.add(Sort.Order.desc(strKey));
                } else {
                    listOrder.add(Sort.Order.asc(strKey));
                }
            }
            sort = Sort.by(listOrder);
        }
        if (ObjectUtil.isNull(sort)) {
            sort = Sort.unsorted();
        }
        return sort;
    }

    /**
     * 得到模型
     *
     * @return {@link M}
     */
    @JsonIgnore
    public M getModel() {
        if (ObjectUtil.isNotNull(model)) {
            return model;
        } else {
            return ReflectUtil.newInstanceIfPossible(this.getClassM());
        }
    }

    /**
     * 得到搜索用map
     *
     * @return {@link Map}<{@link String}, {@link String}>
     */
    public Map<String, String> getMapSearch() {
        if (ObjectUtil.isNull(mapSearch)) {
            mapSearch = new HashMap<>(8);
        }
        return mapSearch;
    }

    /**
     * 添加搜索条件
     *
     * @param strKey   str关键
     * @param strValue str价值
     */
    public void putSearch(String strKey, String strValue) {
        getMapSearch().put(strKey, strValue);
    }

    /**
     * 获取搜索条件的值
     *
     * @param strKey str关键
     * @return {@link String}
     */
    public String getSearchValue(String strKey) {
        return getMapSearch().get(strKey);
    }

    /**
     * 得到对象的class
     *
     * @return {@link Class }<{@link M }>
     */
    @SuppressWarnings("unchecked")
    public Class<M> getClassM() {
        if (ObjectUtil.isNull(classM)) {
            ParameterizedType typeClass = (ParameterizedType) this.getClass().getGenericSuperclass();
            classM = (Class<M>) typeClass.getActualTypeArguments()[0];
        }
        return classM;
    }

    /**
     * 添加排序策略
     *
     * @param strsSortProp 排序属性数组
     */
    public void addSort(String... strsSortProp) {
        addSort(null, strsSortProp);
    }

    /**
     * 过滤过滤map
     *
     * @param strsKey 需保留键数组
     */
    public void filterMapSort(String... strsKey) {
        this.mapSort = MapUtil.filter(this.mapSort, strsKey);
    }

    /**
     * 过滤查询条件map
     *
     * @param strsKey 需保留键数组
     */
    public void filterMapSearch(String... strsKey) {
        // 如果保留数组非空，则继续
        if (ArrayUtil.isNotEmpty(strsKey) && MapUtil.isNotEmpty(mapSearch)) {
            // 遍历map所有记录
            for (String strKey : mapSearch.keySet()) {
                // 判断key是否在数据
                if (ArrayUtil.contains(strsKey, strKey)) {
                    // 在数组中则去掉特殊字符串
                    String strValue = mapSearch.get(strKey);
                    strValue = StrongUtils.replaceAllSpecialCharacter(strValue);
                    mapSearch.put(strKey, strValue);
                }
            }
        }
        this.mapSearch = MapUtil.filter(mapSearch, stringStringEntry -> !StrUtil.isBlank(stringStringEntry.getValue()));
    }

    /**
     * 清除所有排序条件map
     */
    public void cleanMapSort() {
        this.mapSort = null;
    }

    /**
     * 过滤模型的属性
     *
     * @param strsIncludeProperties 模型保留的属性字符串数组
     */
    public void filterModel(String... strsIncludeProperties) {
        // 如果待过滤属性数组和模型对象都存在，则执行过滤
        if (ArrayUtil.isNotEmpty(strsIncludeProperties) && ObjectUtil.isNotNull(model)) {
            setModel(StrongUtils.toBean(model, this.getClassM(), strsIncludeProperties));
        }
    }

    /**
     * 获取分页对象
     *
     * @return {@link Pageable}
     */
    public abstract Pageable getPageable();

    /**
     * 添加排序策略
     *
     * @param direction    排序方式
     * @param strsSortProp 排序属性数组
     */
    public abstract void addSort(Sort.Direction direction, String... strsSortProp);

    /**
     * 添加查询map
     *
     * @param strKey   查询key
     * @param strValue 查询值
     */
    public abstract void addSearch(String strKey, String strValue);

    /**
     * 得到asc字符串
     *
     * @return {@link String}
     */
    @JsonIgnore
    public abstract String getAscString();

    /**
     * 得到desc字符串
     *
     * @return {@link String}
     */
    @JsonIgnore
    public abstract String getDescString();
}
